<?php

/*
 * Plugin Name: SaveLink
 * Plugin URI: -----
 * Description: This plugin creates a copy of a webpage in a local file for selected links in a post.  It replaces the link in a post with the new link 
 * pointing to the local file.  It updates the metadata for a post with the original link and the new link
 * Version: 1.0
 * Author: Mark Tilly
 * Author URL: http://www.memeposts.com
 * License: GPLv2 or later
/*
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

/*TO ADD NEW LOGINS:
 * Update the admin page with the new site
 * Update admin page POST processing to save site key, uname and pass
 * Update mct_sl_replink and add the new sites to the domain string append process at top
 * Update mct_sl_writepage to handle the new login and call
 * the new function which you also add
 */
/* Transients used to store original and new links (or error messages) between filter and post_save hook
 * mct_sl_origlink  - Original link
 * mct_sl_newlink - new link or error message
 * MetaData used to store links for post
 * mct_sl_origurl - original url
 * mct_sl_newurl  - new url ondisk
 */
//Disable Revisions - cause lots of problems with meta data and repeated updates
define('WP_POST_REVISIONS', false);
//Activation hook: Check for the directory and create it if not found
register_activation_hook(__FILE__, 'mct_sl_activehook');
//Set up filter on wp_insert_data
add_filter('wp_insert_post_data','mct_sl_replink');
//Set up filter on postie to strip tags on html
//Postie can introduce style options in p and a tags 
//so clean that up too
add_filter('postie_post','mct_sl_postie');
// Directory for saved pages
define("MCT_SL_SAVEPAGES","mct-sl-savelink");
//SaveLink key
define("MCT_SL_SAVEKEY","sl:");
//Global options array
$mct_sl_optarray = get_option('mct_sl_options');
// Add hook save_post to store the original/new link in metadata
add_action('save_post','mct_sl_savelinkmeta');
//Metabox to show link data
add_action('add_meta_boxes','mct_sl_linkmeta');
//Admin Options page, single menu entry
add_action('admin_menu','mct_sl_addmenu');
//Set up the settings for the admin menu
//add_action('admin_init','mct_sl_admin_init');
//Remove file from disk if deleting post
add_action('before_delete_post','mct_sl_deletefile');
//Get login functions
include('savelink_fcns.php');

function mct_sl_activehook(){
    //Create the directory if not there
    global $mct_sl_optarray;
    $directoryName = MCT_SL_SAVEPAGES;
    if( !is_dir(ABSPATH.$directoryName) ){
	//make directory
	if( !mkdir( ABSPATH.$directoryName, 0755 ) ){
		die('Directory '.$directoryName.' could not be created!');
	}
    }
    if (empty($mct_sl_optarray)){
        add_option('mct_sl_options');
    }
}

function mct_sl_deletefile($post_id){
    //Get the meta data, and delete the new url's from disk
    $newlinks = get_post_meta($post_id,'mct_sl_newurl',true);
    for ($i=0;$i<count($newlinks);$i++){
        $pos = stripos($newlinks[$i],MCT_SL_SAVEPAGES);
        if ($pos !== false){
            $filename = ABSPATH.substr($newlinks[$i],$pos);
            if (stripos(ABSPATH,'\\') !== false) {
                $filename = str_ireplace('/','\\',$filename); // Backslashed file system, so change all
            }
            $filename = trim($filename);
            if (file_exists($filename))
                    $ret = unlink($filename);
        }
    }
}

function mct_sl_postie($content){
    //Set postie to allow html in the body
    //but strip all tags except p, a
    $stripped =  strip_tags($content['post_content'],'<p><a>');
    //Get rid of Style tags and other stuff
    //<p ....> should just be <p> ie get rid of style, ID etc
    $stripped = preg_replace('{<p[^>]*>}','<p>',$stripped);
    //<a ...  href  ... >  get rid of style info    
    $stripped = preg_replace('{<a ([^>]*)style\s*=\s*("|\')([^"\']*)("|\')([^>]*)>}i','<a $1$5>',$stripped);
    $content['post_content'] = $stripped;
    return $content;
}
function mct_sl_replink($data){
/*Find the save link key sl: and check the do all flag
 *If found, find the link in the post - all of them
 * If not, check the options for specific domains
 *Write the web pages out to disk
 *Replace the link with the saved file
 *Write transient for 'save_post' hook with the original url and the new saved file (or error message if we couldn't save and leave sl key)
 */
    global $mct_sl_optarray;
    $slkey = MCT_SL_SAVEKEY;
    //is this not final, if so return
    if (in_array( $data['post_status'], array( 'draft', 'pending', 'auto-draft', 'inherit' )))
        return $data;
        
    $post_dat = $data['post_content'];
    
    //See if we are to replace all links
    $has_key = false;
    $do_all = false;
    if ($mct_sl_optarray['save_all_pages'] == '1'){
        $do_all = true;
    }
    if (stripos($post_dat,$slkey) !== false) {
        $has_key = true;
        $do_all = true;  //same as do all
    }
    // get the links, try escaped and unescaped quotes
    $link_arr = array();
    $num_links = 0;
    $regexp = '{<a [^>]*href\s*=\s*(\\\\"|.\')([^"\']*)(\\\\"|.\')[^>]*>}i';  //used .\' because couldn't end up with \' 
    $num_links1 = preg_match_all($regexp,$post_dat, $matches1);
    $regexp = '{<a [^>]*href\s*=\s*("|\')([^"\']*)("|\')[^>]*>}i';  //Try unescaped - email posts and press-this
    $num_links2 = preg_match_all($regexp,$post_dat, $matches2);
    if ($num_links1 != 0){
        foreach($matches1[2] as $lnk){
            array_push($link_arr,$lnk);
        }
        $num_links += $num_links1;
    }
    if ($num_links2 != 0){
        foreach($matches2[2] as $lnk){
            array_push($link_arr,$lnk);
        }
        $num_links += $num_links2;
    }
    //Any links to replace?
    if ($num_links == 0)
        return $data;  //nothing to do, no links
        
    if ($do_all == false) {
        //Get the domains to search for
        $domains = $mct_sl_optarray['domain_string'];
        //Expand the domain string with any login sites, first check if already included
        if ($mct_sl_optarray['ft_site'] != ''){
            if (stripos($domains,$mct_sl_optarray['ft_site']) === false){
                $domains .= "\n".$mct_sl_optarray['ft_site'];
            }
        }
        if ($mct_sl_optarray['wsj_site'] != ''){
            if (stripos($domains,$mct_sl_optarray['wsj_site']) === false){
                $domains .= "\n".$mct_sl_optarray['wsj_site'];
            }
        }
        if ($mct_sl_optarray['nyt_site'] != ''){
            if (stripos($domains,$mct_sl_optarray['nyt_site']) === false){
                $domains .= "\n".$mct_sl_optarray['nyt_site'];
            }
        }
        //Done with login sites
    }
    //Check if domains to do
    if ($do_all == false && strlen($domains) == 0)
        return $data; // Nothing to do, no auto domains or do all

    //Set up some variables
    $any_error = false;
    $new_alinks = array();
    $old_alinks = array();
    
    if ($do_all == true){
        //For all link matches, replace the url with a local copy
        foreach ($link_arr as $oldlink) {
           // Make sure this hasn't been replace already
           if (stripos($oldlink,site_url())!== false)
                   continue;
        
           //Get the url and create a copy on disk        
           $newlink  = mct_sl_writepage($oldlink);
           if ($newlink == ''){
               //Save failed so put in error text
               $newlink = "Error: Could not save a copy of web page";
               $any_error = true;
           }
           else {
               $newlink = site_url().$newlink;  // add the url to the link
               //replace the link in the text
               $post_dat = str_ireplace($oldlink,$newlink,$post_dat);
           }
           //Load our links array
           array_push($new_alinks,$newlink);
           array_push($old_alinks,$oldlink);
        }
    }
    else {//else - look for autoreplace elements
        $dom_array = explode("\n",$domains);
        foreach ($dom_array as $dom) {
            $dom = rtrim($dom);
            foreach ($link_arr as $oldlink) {
                $linkhost = parse_url($oldlink, PHP_URL_HOST);  //only check the host/domain as we could get problems with path/query
                if (stripos($linkhost,$dom) !== false) {
                    //Get the url and create a copy on disk        
                   $newlink  = mct_sl_writepage($oldlink);
                   if ($newlink == ''){
                       //Save failed so put in error text
                       $newlink = "Error: Could not save a copy of web page";
                       $any_error = true;
                   }
                   else {
                       $newlink = site_url().$newlink;  // add the url to the link
                       //replace the link in the text
                       $post_dat = str_ireplace($oldlink,$newlink,$post_dat); 
                   }
                   //Load our links array
                   array_push($new_alinks,$newlink);
                   array_push($old_alinks,$oldlink);
                }
            }
        }
    }

    //Put links into transients for storage if we have anything
    if (count($old_alinks) != 0){
        $trans = array('old' => $old_alinks,
                       'new' => $new_alinks);
        set_transient('mct_sl_transmeta',$trans,300);
    }

    //if !error replace the save key
    if (!$any_error && $has_key)
        $post_dat = str_ireplace($slkey,'',$post_dat);

    //Replace $data with $post_dat in case we replaced some links
    $data['post_content'] = $post_dat;
    return $data;
        
}
function mct_sl_writepage($url){
    //Write the web page to disk, return the new file name or '' if failed
    global $mct_sl_optarray;
    
    $directoryName = MCT_SL_SAVEPAGES;
    $filename = "/".md5( $url );
    $extension = ".html";
    $full_name = ABSPATH.$directoryName.$filename.$extension;
    if (stripos(ABSPATH,'\\') !== false) {
        $full_name = str_ireplace('/','\\',$full_name); // Backslashed file system, so change all
    }
    $i = 0;
    while (file_exists($full_name)){
        $filename .= 'z';  //On disk already, so make unique 
        $full_name = ABSPATH.$directoryName.$filename.$extension;
        if (stripos(ABSPATH,'\\') !== false) {
            $full_name = str_ireplace('/','\\',$full_name); // Backslashed file system, so change all
        }
        $i++;
        if ($i > 9) break;  //enough already
    }
    $pageContent = '';
    //
    //Check for login domains - these take precedence
    // (add new here)
    $login_type = false;
    $linkhost = parse_url($url, PHP_URL_HOST);
    if ($mct_sl_optarray['ft_site'] != '' && stripos($linkhost,$mct_sl_optarray['ft_site']) !== false){
        $login_type = true;
        $pageContent = ft_login($url);
    }
    if ($mct_sl_optarray['wsj_site'] != '' && stripos($linkhost,$mct_sl_optarray['wsj_site']) !== false){
        $login_type = true;
        $pageContent = wsj_login($url);
    } 
    if ($mct_sl_optarray['nyt_site'] != '' && stripos($linkhost,$mct_sl_optarray['nyt_site']) !== false){
        $login_type = true;
        $pageContent = nyt_login($url);
    }
    //Not a login type so use standard capture
    if (!$login_type){
        $pageContent = file_get_contents($url); 
    }
    if ($pageContent == '')
        return '';
    $h = fopen($full_name, "w+");
    if ($h == false)
            return '';
    if (fwrite($h, $pageContent) == false)
            return '';
    fclose($h);
    return '/'.$directoryName.$filename.$extension;

}

function mct_sl_savelinkmeta($post_id){
    //Called on post_save hook, save data from the globals to meta data
    $trans = get_transient('mct_sl_transmeta');
    if ($trans === false) 
        return; //no meta data
    $newlink = $trans['new'];
    $oldlink = $trans['old'];
    
    //Check for existing meta and add on to new meta if found
    $orig_links = get_post_meta($post_id,'mct_sl_origurl',true);
    $new_links = get_post_meta($post_id,'mct_sl_newurl',true);
    if ($orig_links != '') {
        foreach ($orig_links as $link){
            array_push($oldlink,$link);
        }
    }
    if ($new_links != ''){
        foreach ($new_links as $link) {
            array_push($newlink,$link);
        }
    }

    update_post_meta($post_id,'mct_sl_origurl',$oldlink);
    update_post_meta($post_id,'mct_sl_newurl',$newlink);
   
    delete_transient('mct_sl_transmeta');  //Get rid of this so we don't find it later
}

function mct_sl_linkmeta(){
    add_meta_box('mct_sl_metabox','Link Replacement for SaveLink','mct_sl_linkmetashow','post','normal','high');
}

function mct_sl_linkmetashow($post){
    $origlinks = get_post_meta($post->ID,'mct_sl_origurl',true);
    $newlinks = get_post_meta($post->ID,'mct_sl_newurl',true);
    for ($i=0;$i<count($origlinks);$i++){
        echo '<p>Original URL: '.$origlinks[$i].'</p>';
        echo '<p>New URL:      '.$newlinks[$i].'</p>';
    }
}

/* The functions below create and use the SaveLink admin page.  
 
 */
function mct_sl_addmenu(){
    add_options_page('SaveLink','SaveLink','manage_options',basename(__FILE__),'mct_sl_options_page');
}

//Page to display the form
function mct_sl_options_page() {
    

    if (isset($_POST['Submit']) ) {
        //Check domain string and strip out spaces, extra \n
        $valid_str = '';
        $varray = explode("\n",$_POST['domain_string']);
        foreach ($varray as $vstr){
            $vstr = trim($vstr);
            if (strlen($vstr) != 0){
                $valid_str .= $vstr."\n";
            }
        }
        $valid_str = trim($valid_str);
        //Check logins and set sites if filled in, a blank site name means don't use it
        if (empty($_POST['ft_uname']) || empty($_POST['ft_pass']))
            $ft_site = '';
        else
            $ft_site = '.ft.com';
        
        if (empty($_POST['wsj_uname']) || empty($_POST['wsj_pass']))
            $wsj_site = '';
        else
            $wsj_site = 'online.wsj.com';
        
        if (empty($_POST['nyt_uname']) || empty($_POST['nyt_pass']))
            $nyt_site = '';
        else
            $nyt_site = 'nytimes.com';        
        
        //load options into array and update db
        $opt_update = array (
            'domain_string' => $valid_str,
            'save_all_pages' => $_POST['save_all_pages'],
            'ft_uname' => $_POST['ft_uname'],
            'ft_pass' => $_POST['ft_pass'],
            'ft_site' => $ft_site,  //Load the site domain
            'wsj_uname' => $_POST['wsj_uname'],
            'wsj_pass' => $_POST['wsj_pass'],
            'wsj_site' => $wsj_site,  //Load the site domain
            'nyt_uname' => $_POST['nyt_uname'],
            'nyt_pass' => $_POST['nyt_pass'],
            'nyt_site' => $nyt_site  //Load the site domain
            
        );
        update_option('mct_sl_options',$opt_update);
    }
    //Get the current option values from db
    $cur_options = get_option('mct_sl_options');
    
    ?>
<div class='wrap'>
    <?php screen_icon('link-manager'); ?>
    <h2>SaveLink</h2>
    <p>The SaveLink plugin allows you to create a local copy of a web page that you have linked to in one of your posts.
        You won't have to worry about whether the page is moved or deleted or placed behind a pay-wall.  
    </p>
    <h3>Manual and Automatic Saving</h3>
    <p>To manually save a copy of a web page, enter the SaveLink key anywhere in the body of the post (not the title). 
        All of the links in the post will be saved, not just a single one.  Only well-formatted links will be saved.  
        The SaveLink key will be removed from the post when the web page has been saved and the link will be updated 
        to point to the new saved page.  In order to preserve your formatting, it is best to enter the SaveLink key at the
        beginning or end of a line - but it is not necessary. </p>
    <p><strong>The SaveLink key is <?php echo MCT_SL_SAVEKEY; ?> </strong></p>
    <p>Check the checkbox to save all pages locally, no matter which site they are from.  Alternately, you may be selective and
        enter a set of domains or sites that will have the links to their pages automatically saved.
        You do not need to enter the complete domain, just a portion that is unique enough to match the site without 
        matching other possible sites.  For example entering wsj for the Wall Street Journal site could also match a site
        named wsjobs.  Enter as many domains in the text box as you would like.</p>
    <form method="post" action="<?php echo $_SERVER['PHP_SELF'] . '?page=' . basename(__FILE__); ?>&updated=true">
        <table class="form-table" >
            <tr>
                <th scope="row">Save All Pages?</th>
                <td><input name="save_all_pages" type="checkbox" id="save_all_pages" value="1" <?php checked('1', $cur_options['save_all_pages']); ?>"  /></td></td>    
            </tr>
            <tr>
                <th scope="row">Enter Domains</th>
                <td><textarea id='domain_string' rows='10' cols='50' name='domain_string'><?php echo $cur_options['domain_string'] ?></textarea>"</td>    
            </tr>
        </table>
            <h3>Saving pages using a login</h3>
            <p>By entering the username and password of your account for any of the following sites, the pages will be saved
                automatically from that site.  The account will be used to login so that the page may be accessed.  If you enter
                information in this section, you do not need to enter the site into the domains above.</p>
        <table class="widefat" >
            <thead>
                <tr>
                <th>Site</th>
                <th>Username</th>
                <th>Password</th>
                </tr>
            </thead>
            <tbody>
            <tr>
                <th scope="row">Financial Times Login</th>
                <td><input type ="text" id="ft_uname" maxlength="100" size ="30" name="ft_uname" value ="<?php echo $cur_options['ft_uname'] ?>" /></td>
                <td><input type ="password" id="ft_pass" maxlength="40" size ="20" name="ft_pass" value ="<?php echo $cur_options['ft_pass'] ?>" /></td>
            </tr> 
            <tr>
                <th scope="row">Wall Street Journal Login</th>
                <td><input type ="text" id="wsj_uname" maxlength="100" size ="30" name="wsj_uname" value ="<?php echo $cur_options['wsj_uname'] ?>" /></td>
                <td><input type ="password" id="wsj_pass" maxlength="40" size ="20" name="wsj_pass" value ="<?php echo $cur_options['wsj_pass'] ?>" /></td>
            </tr> 
            <tr>
                <th scope="row">New York Times Login</th>
                <td><input type ="text" id="nyt_uname" maxlength="100" size ="30" name="nyt_uname" value ="<?php echo $cur_options['nyt_uname'] ?>" /></td>
                <td><input type ="password" id="nyt_pass" maxlength="40" size ="20" name="nyt_pass" value ="<?php echo $cur_options['nyt_pass'] ?>" /></td>
            </tr> 
            </tbody>
        </table>
        <div class="submit">
            <input name="Submit" type="submit" value="Save Options" class="button-primary" />
        </div>
        </form>
</div>
<?php
}
?>
